package com.hd.quartz.util;

import com.hd.quartz.common.FieldNameConstants;
import com.hd.quartz.entity.ScheduleJobEntity;
import com.hd.quartz.entity.ScheduleJobLogEntity;
import com.hd.quartz.service.ScheduleJobLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;

/**
 * <h3>partitionjob</h3>
 * <p>ScheduleJob</p>
 *
 * @author : hduong
 * @version : 1.0
 * @date : 2020-09-11 16:34
 **/
@Slf4j
public class ScheduleJob extends QuartzJobBean {


    /**
     * 单例 线程池
     */
    private ExecutorService service = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>());

    private ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //1: 获取任务实体类 (来自 任务执行上下文对象 jobExecutionContext)
        //2: 记录执行日志 : 获取 spring 日志bean
        //3: 通过反射执行任务具体方法
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        if (jobDetail == null) {
            throw new JobExecutionException("任务详情为空!");
        }
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        log.info("jobDataMap: {}", jobDataMap);
        if (jobDataMap == null || jobDataMap.size() == 0) {
            log.info("任务参数为空: jobDataMap = {}", jobDataMap);
        } else {

        }
        //获取spring bean
        ScheduleJobLogService scheduleJobLogService = (ScheduleJobLogService) SpringContextUtil.getBean("scheduleJobLogService");

        JobDataMap jobEntityDataMap = jobExecutionContext.getMergedJobDataMap();
        if (jobEntityDataMap == null) {
            throw new JobExecutionException("任务对象参数为空!");
        }
        Set<Map.Entry<String, Object>> entrySet = jobDataMap.entrySet();
        ScheduleJobEntity jobEntity = null;
        for (Map.Entry<String, Object> entry : entrySet) {
//            jobEntity = (ScheduleJobEntity) jobEntityDataMap.get(ScheduleJobEntity.JOB_PARAM_KEY);
            String key = entry.getKey();
            if (ScheduleJobEntity.JOB_PARAM_KEY.equals(key)) {
                jobEntity = (ScheduleJobEntity) entry.getValue();
            }
        }

        //获取spring bean : 0表示非批量任务
        if (jobEntity != null && jobEntity.getIsBatchJob() == 0) {
            //构造日志对象
            ScheduleJobLogEntity jobLogEntity = new ScheduleJobLogEntity();
            //1:
            jobLogEntity.setJobId(jobEntity.getJobId());
            jobLogEntity.setBeanName(jobEntity.getBeanName());
            jobLogEntity.setMethodName(jobEntity.getMethodName());
            jobLogEntity.setParams(jobEntity.getParams());
            jobLogEntity.setCreateTime(new Date());

            //任务开始时间
            //任务开始时间
            long startTime = System.currentTimeMillis();
            try {
                //执行任务
                log.info("任务准备执行，任务ID：" + jobEntity.getJobId());
                ScheduleRunnable scheduleRunnable = new ScheduleRunnable(jobEntity.getBeanName(),
                        jobEntity.getMethodName(), jobEntity.getParams());
                Future<?> future = singleThreadExecutor.submit(scheduleRunnable);

                //阻塞 知道执行完任务
                future.get();

                long times = System.currentTimeMillis() - startTime;
                //任务执行总时长
                jobLogEntity.setTimes((int) times);
                //任务状态    0：成功    1：失败
                jobLogEntity.setStatus(0);

                log.info("任务执行完毕，任务ID：" + jobEntity.getJobId() + "  总共耗时：" + times + "毫秒");
            } catch (Exception e) {
                log.error("任务执行失败，任务ID：" + jobEntity.getJobId(), e);

                //任务执行总时长
                long times = System.currentTimeMillis() - startTime;
                jobLogEntity.setTimes((int) times);

                //任务状态    0：成功    1：失败
                jobLogEntity.setStatus(1);
                jobLogEntity.setError(StringUtils.substring(e.toString(), 0, 2000));
            } finally {
                scheduleJobLogService.save(jobLogEntity);
            }
        } else if (jobEntity != null && jobEntity.getIsBatchJob() == 1) {
            //批量任务执行步骤
            //1: 新增 批量任务定义
            //2: quartz表中新增该任务定义
            //3: 设置启动方式
            JobDetail jobExecutionContextJobDetail = jobExecutionContext.getJobDetail();
            JobDataMap jobDetailJobDataMap = jobExecutionContextJobDetail.getJobDataMap();
//            Job job = (Job) jobDetailJobDataMap.get(ScheduleJobEntity.BATCH_JOB_KEY);
            String jobName = (String) jobDetailJobDataMap.get(ScheduleJobEntity.BATCH_JOB_KEY);
            Job job = (Job) SpringContextUtil.getBean(jobName);
//            JobLauncher jobLauncher = (JobLauncher) jobDetailJobDataMap.get(ScheduleJobEntity.BATCH_JOB_LAUNCHER_KEY);
            JobLauncher jobLauncher = (JobLauncher) SpringContextUtil.getBean(ScheduleJobEntity.BATCH_JOB_LAUNCHER_KEY);
            log.info("批量job :{}", job);
            log.info("批量jobLauncher :{}", jobLauncher);

            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String date = sf.format(new Date());
            ScheduleJobLogEntity jobLogEntity = new ScheduleJobLogEntity();
            //1:
            jobLogEntity.setJobId(jobEntity.getJobId());
            jobLogEntity.setBeanName(jobEntity.getBeanName());
            jobLogEntity.setMethodName(jobEntity.getMethodName());
            jobLogEntity.setParams(jobEntity.getParams());
            jobLogEntity.setCreateTime(new Date());
            long startTime = System.currentTimeMillis();
            try {
                log.info("当前时间 :{},当前执行任务:{}", date, job);
                JobParameters jobParameters = new JobParametersBuilder()
                        .addDate(FieldNameConstants.OTHER_CONST_DATE, new Date())
                        .toJobParameters();
                jobLauncher.run(
                        job, jobParameters);
                log.info("**********************job:{}执行完毕****************", job);
                long times = System.currentTimeMillis() - startTime;
                //任务执行总时长
                jobLogEntity.setTimes((int) times);
                //任务状态    0：成功    1：失败
                jobLogEntity.setStatus(0);

                log.info("任务执行完毕，任务ID：" + jobEntity.getJobId() + "  总共耗时：" + times + "毫秒");
            } catch (Exception e) {
                log.error("发生异常{}", e);
                log.error("任务执行失败，任务ID：" + jobEntity.getJobId(), e);

                //任务执行总时长
                long times = System.currentTimeMillis() - startTime;
                jobLogEntity.setTimes((int) times);

                //任务状态    0：成功    1：失败
                jobLogEntity.setStatus(1);
                jobLogEntity.setError(StringUtils.substring(e.toString(), 0, 2000));
            } finally {
                scheduleJobLogService.save(jobLogEntity);
            }
        }
    }
}
